﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;

namespace DigitalQuran.Threading {    

    /// <summary>
    /// Do Initialize Operations in background
    /// </summary>
    public class AppInitializer {

        BackgroundWorker worker;

        /// <summary>
        /// Create new instance
        /// </summary>
        public AppInitializer() {
            Operations = new BackgroundOperationsQueue();

            worker = new BackgroundWorker();
            worker.WorkerSupportsCancellation = true;            

            worker.DoWork += WorkerJob;            
            worker.RunWorkerCompleted += WorkerJobCompleted;
        }

        /// <summary>
        /// Gets Queue of Background Operation
        /// </summary>
        public BackgroundOperationsQueue Operations { get; private set; }

        /// <summary>
        /// Starts the Job
        /// </summary>
        public void DoJob() {
            worker.RunWorkerAsync();

            resetEvent.Reset();
            resetEvent.WaitOne();
        }

        static ManualResetEvent resetEvent = new ManualResetEvent(true);

        /// <summary>
        /// Stop the Job
        /// </summary>
        public void AbortJob() {
            worker.CancelAsync();
        }

        /// <summary>
        /// Gets or sets the function to call before starting an operation. Function will get Progress Percentage and Operation Message as argument
        /// </summary>
        public Action<int, string> ExecuteProgress { get; set; }

        public Action JobCompleted { get; set; }

        private void WorkerJob(object sender, DoWorkEventArgs e) {
            int i = 1;
            while (Operations.HasItems && !worker.CancellationPending) {
                var op = Operations.Dequeue();
                ExecuteProgress(Convert.ToInt32(((i - 1) / Convert.ToDouble(i + Operations.Count)) * 100), op.Message);
                op.Action();
                i++;
            }

            Operations.Clear();
            ExecuteProgress(100, "Cleaning Up...");
            GC.Collect();
            GC.WaitForPendingFinalizers();

            resetEvent.Set();
        }

        private void WorkerJobCompleted(object sender, RunWorkerCompletedEventArgs e) {
            if (JobCompleted != null)
                JobCompleted();
        }
    }
}